Skip to content

feat(title): add recipe and tokens - #31539

Open
thetaPC wants to merge 8 commits into
FW-6863-testsfrom
FW-6863
Open

thetaPC wants to merge 8 commits into
FW-6863-testsfrom
FW-6863

Conversation

@thetaPC

@thetaPC thetaPC commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Issue number: resolves internal


What is the current behavior?

ion-title does not fragment styles based on themes.

What is the new behavior?

  • Migrates ion-title to Modular Ionic: one token-driven stylesheet, IonTitleRecipe and IonTitleConfig, and per-theme token defaults for ios, md and ionic.
  • Adds a hue prop (bold by default, or subtle). The ionic theme now applies color, matching ios and md.
  • The ionic title's padding moves from the toolbar into the title's tokens, so an ionic title outside a toolbar now gets the same inline padding as ios and md.
  • size accepts medium, which is the default from the new IonTitle.size config. The header's condense effect also reads that config, so a title made large through it condenses. Size classes are now title-size-small, title-size-medium and title-size-large, and toolbar's matching classes are toolbar-title-size-*.
  • Replaces --color with --ion-title-color, which also reaches the copy of a large title shown during the iOS page transition.
  • Removes runtime theme branching (getIonTheme and the theme virtual prop) and the title-rtl class.
  • Removes the iOS toolbar's large title rule and its title-large order value. The rule's selector can't reach the slotted title, so it never applied, and the title already computes order: 0. Rendering doesn't change.
  • Adds a dynamicFontMax token helper, and rounds scaled sizes in dynamicFontMin and dynamicFontMax.
  • Snapshot changes: the ionic title-color screenshots now show colored titles. In header's "root iOS header in an MD app" screenshot, the title follows the page's theme: an ancestor mode attribute now only affects behavior, as it already does for every migrated component.

Does this introduce a breaking change?

  • Yes
  • No

ion-title CSS variables and classes are replaced by token-driven custom properties and prop-named classes. Use the global token for theme-wide styling, or the CSS variable for component-specific overrides.

  1. Color
Old Token (global) CSS variable (component-specific)
--color IonTitle.color --ion-title-color
  1. Size classes
Old New
title-default title-size-medium
title-small title-size-small
title-large title-size-large
toolbar-title-default toolbar-title-size-medium
toolbar-title-small toolbar-title-size-small
toolbar-title-large toolbar-title-size-large
  1. RTL class: title-rtl is removed. Use ion-title:dir(rtl) instead.

  2. Theme classes: remove any instances that target ion-title.md or ion-title.ios.

Other information

Left for the parents

Some ion-title styles still live in, or depend on, its parents. They move with that parent's work, so they aren't part of this PR.

  • Toolbar titlePlacement: the text-align rules in toolbar.ionic.scss, and the iOS title's own centering in title.scss (marked with TODOs). A follow-up PR stacked on this one makes titlePlacement work in every theme and removes both.
  • Header scroll effects: the rules in header.common.scss that hide and fade the title as the large title collapses. They depend on the header's scroll state and include its condense motion, so they move in the header migration (FW-6843).

How to test

Open each before and after link side by side.

Check Before After What to look for
Color, ionic theme before after Before, every title is dark gray. After, each title is drawn in the color it names, as in ios and md
Hue, every theme none, new page ios, md and ionic The bold titles use the full color, and the subtle titles a muted one. ios uses the same hue colors as md, so its screenshots only cover md
No theme before after Before, titles use the md styles. After, they render as plain text with no padding, which is how a migrated component looks without a theme
Basic, ios theme before after Looks the same on both
Basic, md theme before after Looks the same on both
Basic, ionic theme before after Looks the same on both, including the titles' padding, which now comes from the title instead of the toolbar

@thetaPC
thetaPC added this pull request to stack #31538 October 6, 2026 22:14
@vercel

vercel Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ionic-framework Ready Ready Preview Oct 12, 2026 3:38pm UTC

Request Review

@github-actions github-actions Bot added package: core @ionic/core package package: angular @ionic/angular package package: vue @ionic/vue package package: react @ionic/react package labels Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The title in this snapshot now follows the page's md theme instead of the header's mode="ios", since migrated components take their look from the theme and mode only affects behavior; the header itself is still visible, which is what the test checks.

@thetaPC thetaPC mentioned this pull request Oct 12, 2026
1 of 2 tasks
@thetaPC
thetaPC marked this pull request as ready for review October 12, 2026 18:13
@thetaPC
thetaPC requested a review from a team as a code owner October 12, 2026 18:13
@thetaPC
thetaPC requested a review from ShaneK October 12, 2026 18:13

@brandyscarney brandyscarney left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I requested some changes. 🙂

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need both a color folder and a hue folder? Shouldn't we just have the hue folder since the color has to be either bold or subtle?

// --------------------------------------------------
// We're using the slots to force the main toolbar content to be
// centered in the toolbar. This is a bit of a hack but it works.
// centered in the toolbar. This is a bit of a hack butx it works.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// centered in the toolbar. This is a bit of a hack butx it works.
// centered in the toolbar. This is a bit of a hack but it works.

/**
* This behavior does not vary across directions.
*
* `ios` is the same as `md`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we skipping ios? All themes will ship with the same colors so eventually they will all be the same.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be named title.interfaces.ts to match the other recipes?

badge.interfaces.ts
chip.interfaces.ts

Comment on lines +1079 to +1081
height: '100%',
position: 'relative',
width: '100%',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are width and height defined here when they are always 100% for every size?

*/
export const isLargeTitle = (ionTitleEl: HTMLIonTitleElement) => {
const attributeSize = ionTitleEl.getAttribute('size') as IonTitleSize | null;
const configSize = config.getObjectValue('IonTitle.size') as IonTitleSize | undefined;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking, possible follow-up for FW-6843

size now does two jobs: it sets how big the title looks, and size="large" also marks the title that collapses (here, and in the ion-title.title-size-large query in ios.transition.ts). Now that size is in the theme config, an app that sets IonTitle: { size: 'large' } would make every title large, including main-header titles. Those would then get the large-title layout and count as collapsing titles.

Could the header migration work out the collapsing title from where it sits rather than from its size? For example, treat the title inside ion-header[collapse="condense"] as the collapsing title. Then size would only control appearance, and an app-wide size default would be harmless.

This wouldn't break anything: size="large" would keep working, it just wouldn't be required, and the "condense requires <ion-title size="large">" warning could go away. Fine to leave as is for this PR.

width?: string;
};

minWidth?: string;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minWidth is only set so the iOS large title wraps onto its own row, and that only works together with the iOS toolbar's flex-wrap. Could it move into toolbar.ios.scss next to that rule as :host(.toolbar-title-size-large) ::slotted(ion-title) { min-width: 100%; } and the token be dropped? That keeps the wrap behavior in one place, and ::slotted reaches the title where the removed .toolbar-content ion-title rule didn't.

Comment thread BREAKING.md
| `toolbar-title-small` | `toolbar-title-size-small` |
| `toolbar-title-large` | `toolbar-title-size-large` |

<h5 id="version-10x-title-rtl-class">`title-rtl` class</h5>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<h5 id="version-10x-title-rtl-class">`title-rtl` class</h5>
<h5 id="version-10x-title-rtl-class"><code>title-rtl</code> class</h5>

Comment thread BREAKING.md
|---|---|---|
| `--color` | `IonTitle.color` | `--ion-title-color` |

<h5 id="version-10x-title-hue">New `hue` property and color tokens</h5>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<h5 id="version-10x-title-hue">New `hue` property and color tokens</h5>
<h5 id="version-10x-title-hue">New <code>hue</code> property and color tokens</h5>

Comment thread BREAKING.md
Comment on lines +573 to +579
`ion-toolbar` builds its own classes from these, so they change as well:

| Old (9.x) | New |
|---|---|
| `toolbar-title-default` | `toolbar-title-size-medium` |
| `toolbar-title-small` | `toolbar-title-size-small` |
| `toolbar-title-large` | `toolbar-title-size-large` |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this go in toolbar's section instead?

This branch was successfully deployed

1 active deployment
Preview — 035a4eeb Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: angular @ionic/angular package package: core @ionic/core package package: react @ionic/react package package: vue @ionic/vue package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants